{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Interactive Graphic Method\n", "\n", "## Try me\n", " [![Open In Colab](../../_static/colabs_badge.png)](https://colab.research.google.com/github/ffraile/operations-research-notebooks/blob/main/docs/source/CLP/tutorials/Graphic%20solution%20interactive.ipynb)[![Binder](../../_static/binder_badge.png)](https://mybinder.org/v2/gh/ffraile/operations-research-notebooks/main?labpath=docs%2Fsource%2FCLP%2Ftutorials%2FGraphic%20solution%20interactive.ipynb)\n", "\n", "## Introduction\n", "In this notebook, you can experiment with the graphic representation of a linear programming problem. The objective is \n", "to gain understanding on the graphic method, how constraints affect the boundaries of the feasibility region and why \n", "the solution to a problem is always at a vertex of the feasibility region. \n", "In this notebook you will be able to change the objective variable and add or remove constraints to experiment and \n", "reflect on these questions. \n", "\n", "## Requirements\n", "This script uses [Numpy](https://numpy.org/), [Matplotlib](https://matplotlib.org/), and [Ipywidgets](https://ipywidgets.readthedocs.io/en/latest/). They are provided off-the-shelf in Colabs. \n", "Otherwise, run the following cell to install in your Kernel:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "!pip install numpy\n", "!pip install matplotlib\n", "!pip install ipywidgets\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Problem model\n", "The problem model is taken from the [Making weapons](https://operations-research.readthedocs.io/en/latest/CLP/exercises/Making%20weapons.html) problem. \n", "You can find the solution here: ([Making weapons](https://operations-research.readthedocs.io/en/latest/CLP/solved/Making%20weapons%20%28solved%29.html))\n", "\n", "$\\max z = 40x_{1} + 5x_{2}$\n", "\n", "s.t. \n", "\n", "$x_{1} + 0.5x_{2} \\leq 125$ (Beskar constraint)\n", "\n", "$x_{1} + x_{2} \\leq 225$ (Tungsten constraint)\n", "\n", "$3x_{1} + x_{2} \\leq 300$ (Titanium constraint)\n", "\n", "$x_{2} \\geq 100$ (Demand constraint)\n", "\n", "The code cell below allows you to add the constraints one by one to see how to modify the feasibility region. \n", "The slider allows to modify the objective variable z to find the optimal value in each case. Remember, the optimal value\n", "will be always the highest value of z where the objective function intersects with the feasibility region. \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Solution with the graphical method" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "f1e2443ecbca4b4e9617f76702081a2b", "version_major": 2, "version_minor": 0 }, "text/plain": [ "interactive(children=(IntSlider(value=3000, description='z', max=6000, step=10), Checkbox(value=False, descrip…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "#Import the numpy and pyplot libraries, we set the aliases np and plt so that it is easier to use \n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "import ipywidgets as widgets\n", "from ipywidgets import interactive\n", "#We set the mode inline of matplotlib to get the result at the output of the cell code\n", "%matplotlib inline\n", "\n", "#Construct lines, in our coordinate system x represents our decision variable x1 and y represents our decision variable x2\n", "x=np.linspace(0,300,2000) #2000 numbers from 0 to 100\n", "\n", "\n", "\n", "y1=(125-x)/0.5 # Beskar constraint \n", "y3=225-x # Tungsten constraint\n", "y4=100+x*0 # Demand constraint\n", "y5=300-3*x # Titanium constraint\n", "\n", "\n", "#1. Interactive plot\n", "def show_solution(z, beskar_constraint, tungsten_constraint, titanium_constraint, demand_constraint):\n", " y_min=x*0 # absolute min: non negativity constraint\n", " y_max = 250 + 0*x # A very high maximum value\n", " plt.figure(1) #Create a figure\n", " # 1. Check if we need to add constraints and recalculate max and min\n", " if beskar_constraint:\n", " plt.plot(x,y1,label=r'$x_{1}+0.5x_{2}\\leq125$')\n", " y_max = np.minimum(y1, y_max)\n", " \n", " if tungsten_constraint:\n", " plt.plot(x,y3,label=r'$x_{1}+x_{2}\\leq225$')\n", " y_max = np.minimum(y3, y_max)\n", " \n", " if titanium_constraint:\n", " plt.plot(x,y5,label=r'$3x_{1}+x_{2}\\leq300$')\n", " y_max = np.minimum(y5, y_max)\n", "\n", " if demand_constraint:\n", " plt.plot(x,y4,label=r'$x_{2}\\geq100$')\n", " y_min = y4\n", "\n", " # 2. Adjust axis\n", " plt.xlim((0,150))\n", " plt.ylim((0,250))\n", " plt.xlabel((r'$x_{1}$'))\n", " plt.ylabel((r'$x_{2}$'))\n", "\n", " # 3. fill between max and min\n", " plt.fill_between(x, y_max, y_min, where=y_max>y_min, color='grey', alpha=0.5)\n", "\n", " # 4. Plot objective function\n", " obj_func= (z - 40*x)/5 # we clear the x2 with the value of z\n", " plt.plot(x, obj_func, label=r'$z = 40*x_1 + 5*x_2$')\n", "\n", " # 5. Plot legend\n", " plt.legend(bbox_to_anchor=(1.05,1), loc=2, borderaxespad=0.)\n", " plt.show()\n", "\n", "interactive_plot = interactive(show_solution, z=(0,6000,10), beskar_constraint = False, tungsten_constraint = False, titanium_constraint = False, demand_constraint = False)\n", "output = interactive_plot.children[-1]\n", "output.layout.height = '350px'\n", "interactive_plot" ] } ], "metadata": { "colab": { "name": "CLP assignment.ipynb", "provenance": [] }, "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.1" }, "pycharm": { "stem_cell": { "cell_type": "raw", "metadata": { "collapsed": false }, "source": [] } } }, "nbformat": 4, "nbformat_minor": 1 }